import { DataSource, Repository, ObjectLiteral, EntityTarget } from 'typeorm';
import { User, CrawlerTask, CrawledData } from '@weubi/shared';
import bcrypt from 'bcryptjs';

export class TestDatabase {
  private static instance: TestDatabase;
  private dataSource: DataSource | null = null;

  private constructor() {}

  static getInstance(): TestDatabase {
    if (!TestDatabase.instance) {
      TestDatabase.instance = new TestDatabase();
    }
    return TestDatabase.instance;
  }

  // 获取全局数据源，确保所有测试组件使用同一个实例
  static getGlobalDataSource(): DataSource | null {
    return (global as any).__TEST_DATA_SOURCE__ || null;
  }

  async connect(): Promise<DataSource> {
    // 优先使用全局数据源
    const globalDataSource = (global as any).__TEST_DATA_SOURCE__;
    if (globalDataSource && globalDataSource.isInitialized) {
      this.dataSource = globalDataSource;
      return this.dataSource!;
    }

    // 如果当前数据源已经初始化，直接返回
    if (this.dataSource?.isInitialized) {
      return this.dataSource;
    }

    // 如果全局数据源存在但未初始化，直接使用它
    if (globalDataSource) {
      this.dataSource = globalDataSource;
      return this.dataSource!;
    }

    const config = (global as any).__TEST_DB_CONFIG__;
    if (!config) {
      throw new Error('测试数据库配置未找到');
    }

    // 如果已经有其他实例在初始化，等待它完成
    if (TestDatabase.initializingPromise) {
      await TestDatabase.initializingPromise;
      if (this.dataSource?.isInitialized) {
        return this.dataSource;
      }
    }

    // 开始初始化
    TestDatabase.initializingPromise = this.initializeDataSource(config);
    await TestDatabase.initializingPromise;
    TestDatabase.initializingPromise = null;

    return this.dataSource!;
  }

  private static initializingPromise: Promise<void> | null = null;

  private async initializeDataSource(config: any): Promise<void> {
    // 确保使用统一导入的实体配置
    const finalConfig = {
      ...config,
      entities: [User, CrawlerTask, CrawledData], // 使用统一导入的实体
    };

    this.dataSource = new DataSource(finalConfig);
    await this.dataSource.initialize();

    // 将初始化的数据源保存到全局变量，确保全局一致性
    (global as any).__TEST_DATA_SOURCE__ = this.dataSource;
  }

  async disconnect(): Promise<void> {
    if (this.dataSource?.isInitialized) {
      await this.dataSource.destroy();
      this.dataSource = null;
    }
  }

  async clearDatabase(): Promise<void> {
    // 优先使用全局数据源
    const globalDataSource = (global as any).__TEST_DATA_SOURCE__;
    const dataSource = globalDataSource || this.dataSource;

    if (!dataSource || !dataSource.isInitialized) {
      throw new Error('数据库未连接或未初始化');
    }

    try {
      // 清空所有表数据，使用更安全的方式
      const entities = dataSource.entityMetadatas;

      // 禁用外键约束
      await dataSource.query('SET session_replication_role = replica;');

      // 清空所有表
      for (const entity of entities) {
        await dataSource.query(`TRUNCATE TABLE "${entity.tableName}" RESTART IDENTITY CASCADE;`);
      }

      // 重新启用外键约束
      await dataSource.query('SET session_replication_role = DEFAULT;');
    } catch (error) {
      console.error('清空数据库失败:', error);
      // 如果TRUNCATE失败，尝试DELETE
      try {
        await dataSource.query('DELETE FROM crawled_data');
        await dataSource.query('DELETE FROM crawler_tasks');
        await dataSource.query('DELETE FROM users');
      } catch (deleteError) {
        console.error('DELETE也失败了:', deleteError);
        throw deleteError;
      }
    }
  }

  getRepository<T extends ObjectLiteral>(entity: EntityTarget<T>): Repository<T> {
    if (!this.dataSource?.isInitialized) {
      throw new Error('数据库未连接');
    }
    // 如果传入的是字符串，直接使用；否则使用实体类
    if (typeof entity === 'string') {
      return this.dataSource.getRepository(entity);
    }
    return this.dataSource.getRepository(entity);
  }

  // 创建测试用户
  async createTestUser(userData: Partial<any> = {}): Promise<any> {
    // 优先使用全局数据源
    const globalDataSource = (global as any).__TEST_DATA_SOURCE__;
    const dataSource = globalDataSource || this.dataSource;

    if (!dataSource || !dataSource.isInitialized) {
      throw new Error('数据源未初始化');
    }

    // 使用字符串名称获取仓库，避免实体实例不匹配
    const userRepo = dataSource.getRepository('User');

    const defaultUser = {
      email: 'test@weubi.com',
      name: 'Test User',
      password: 'test123',
      role: 'user' as const,
      isActive: true,
      emailVerified: true,
      loginCount: 0,
      ...userData
    };

    const user = userRepo.create(defaultUser);
    return await userRepo.save(user);
  }

  // 创建管理员用户
  async createAdminUser(userData: Partial<any> = {}): Promise<any> {
    return this.createTestUser({
      email: 'admin@weubi.com',
      name: 'Admin User',
      role: 'admin',
      ...userData
    });
  }

  // 创建测试任务
  async createTestTask(taskData: Partial<any> = {}): Promise<any> {
    const taskRepo = this.getRepository('CrawlerTask');

    const defaultTask = {
      name: 'Test Task',
      description: 'Test task description',
      url: 'https://example.com',
      config: { selectors: { title: 'h1' } },
      status: 'pending' as const,
      engine: 'http' as const,
      isActive: true,
      priority: 'normal' as const,
      maxRetries: 3,
      ...taskData
    };

    const task = taskRepo.create(defaultTask);
    return await taskRepo.save(task);
  }

  // 创建测试数据
  async createTestData(dataData: Partial<any> = {}): Promise<any> {
    const dataRepo = this.getRepository('CrawledData');

    const defaultData = {
      url: 'https://example.com/page',
      title: 'Test Page',
      content: 'Test content',
      engine: 'http' as const,
      isValid: true,
      isProcessed: false,
      ...dataData
    };

    const data = dataRepo.create(defaultData);
    return await dataRepo.save(data);
  }

  // 批量创建测试用户
  async createTestUsers(count: number, baseData: Partial<any> = {}): Promise<any[]> {
    const users: any[] = [];

    for (let i = 0; i < count; i++) {
      const user = await this.createTestUser({
        email: `test${i}@weubi.com`,
        name: `Test User ${i}`,
        ...baseData
      });
      users.push(user);
    }

    return users;
  }

  // 创建完整的测试场景数据
  async createTestScenario(scenarioName: string) {
    switch (scenarioName) {
      case 'basic_auth':
        return {
          user: await this.createTestUser(),
          admin: await this.createAdminUser()
        };

      case 'with_tasks':
        const user = await this.createTestUser();
        const tasks = await Promise.all([
          this.createTestTask({ name: 'Task 1' }),
          this.createTestTask({ name: 'Task 2', status: 'running' }),
          this.createTestTask({ name: 'Task 3', status: 'completed' })
        ]);
        return { user, tasks };

      case 'inactive_users':
        return {
          activeUser: await this.createTestUser({ isActive: true }),
          inactiveUser: await this.createTestUser({
            email: 'inactive@weubi.com',
            isActive: false
          })
        };

      default:
        throw new Error(`Unknown test scenario: ${scenarioName}`);
    }
  }

  // 验证数据库状态
  async verifyDatabaseState() {
    const userRepo = this.getRepository('User');
    const taskRepo = this.getRepository('CrawlerTask');
    const dataRepo = this.getRepository('CrawledData');

    const counts = {
      users: await userRepo.count(),
      tasks: await taskRepo.count(),
      data: await dataRepo.count()
    };

    return counts;
  }

  // 重置数据库到初始状态
  async resetToInitialState() {
    await this.clearDatabase();

    // 可以在这里添加一些基础数据
    // 比如默认的管理员用户等
  }
}
